using System;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
using System.Diagnostics;
using SharpVectors.Dom.Css;



namespace SharpVectors.Dom.Svg
{
	/// <summary>
	/// SvgStyleableElement is an extension to the Svg DOM to create a class for all elements that are styleable.
	/// </summary>
	public class SvgStyleableElement : SvgElement, ISvgStylable
	{
		#region Private static fields
		private static Regex isImportant = new Regex(@"!\s*important$");
		#endregion

		#region Private Fields
		private Hashtable styleProperties = new Hashtable();
		
		#endregion

		#region Constructors
		internal SvgStyleableElement(string prefix, string localname, string ns, SvgDocument doc) : base(prefix, localname, ns, doc) 
		{
		}
		#endregion

		#region Implementation of ISvgStylable
		#region ClassName
		private ISvgAnimatedString className;
		public ISvgAnimatedString ClassName
		{
			get
			{
				if(className == null)
				{
					className = new SvgAnimatedString(GetAttribute("class", String.Empty));
				}
				return className;
			}
		}
		#endregion

		#region PresentationAttributes
		private Hashtable presentationAttributes = new Hashtable();
		public ICssValue GetPresentationAttribute(string name)
		{
			if(!presentationAttributes.ContainsKey(name))
			{
				ICssValue result;
				string attValue = GetAttribute(name, String.Empty).Trim();
				if(attValue != null && attValue.Length > 0)
				{
					if(isImportant.IsMatch(attValue))
					{
						result = null;
					}
					else
					{
						result = CssValue.GetCssValue(attValue, false);
					}
				}
				else
				{
					result = null;
				}
				presentationAttributes[name] = result;

			}
			return presentationAttributes[name] as ICssValue;
		}
		#endregion
		#endregion

		#region GetValues
		public string GetPropertyValue(string name)
		{
			return GetComputedStyle(String.Empty).GetPropertyValue(name);
		}

		public string GetPropertyValue(string name1, string name2)
		{
			string cssString = GetComputedStyle(String.Empty).GetPropertyValue(name1);
			if(cssString == null)
			{
				cssString = GetComputedStyle(String.Empty).GetPropertyValue(name2);
			}

			return cssString;
		}

		public override ICssStyleDeclaration GetComputedStyle(string pseudoElt)
		{
			if(cachedCSD == null)
			{
				CssCollectedStyleDeclaration csd = (CssCollectedStyleDeclaration)base.GetComputedStyle(pseudoElt);
				
				IEnumerator cssPropNames = OwnerDocument.CssPropertyProfile.GetAllPropertyNames().GetEnumerator();
				while(cssPropNames.MoveNext())
				{
					string cssPropName = (string)cssPropNames.Current;
					CssValue cssValue = (CssValue)GetPresentationAttribute(cssPropName);
					if(cssValue != null)
					{
						csd.CollectProperty(cssPropName, 0, cssValue, CssStyleSheetType.NonCssPresentationalHints, String.Empty);
					}
				}

				cachedCSD = csd;
			}
			return cachedCSD;
		}		
		
		#endregion

		#region Update handling
		public override void HandleAttributeChange(XmlAttribute attribute)
		{
      
      if(attribute.NamespaceURI.Length == 0)
      {
        string localName = attribute.LocalName;
        if(presentationAttributes.ContainsKey(localName))
        {
          presentationAttributes.Remove(localName);                    
        }

        switch(attribute.LocalName)
        {
          case "class":
            className = null;
            // class changes need to propogate to children and invalidate CSS
            break;
        }
      }
      base.HandleAttributeChange(attribute);
		}
		#endregion
	}
}
